package com.xkcyy.one.executor;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xkcyy.one.entity.Script;
import com.xkcyy.one.entity.Tool;
import com.xkcyy.one.exception.BusinessException;
import com.xkcyy.one.service.ScriptService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.tools.*;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

/**
 * 脚本工具执行器
 * 负责执行脚本类型的工具调用
 * 
 * @author yuand
 */
@Component
public class ScriptToolExecutor implements ToolExecutor {

    private static final Logger logger = LoggerFactory.getLogger(ScriptToolExecutor.class);
    private static final String TEMP_DIR = System.getProperty("java.io.tmpdir");

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ScriptService scriptService;

    @Override
    public boolean supports(Tool tool) {
        return tool != null &&
                Tool.ImplementationType.SCRIPT.equals(tool.getImplementationType()) &&
                tool.getScriptId() != null;
    }

    @Override
    public Object execute(Tool tool, Object input) {
        validateInput(tool, input);

        try {
            // 获取脚本
            Long scriptId = tool.getScriptId();
            Script script = scriptService.getScriptById(scriptId);

            // 检查脚本是否编译通过
            if (script.getCompiled() == null || !script.getCompiled()) {
                throw new BusinessException("脚本未编译或编译失败，请先编译脚本");
            }

            // 执行脚本
            Object result = executeScript(script, input);

            // 返回执行结果
            return result;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            logger.error("执行脚本工具失败: " + e.getMessage(), e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("error", true);
            errorResult.put("message", "执行脚本工具失败: " + e.getMessage());
            return errorResult;
        }
    }

    @Override
    public void validateInput(Tool tool, Object input) {
        if (tool == null) {
            throw new IllegalArgumentException("工具定义不能为空");
        }

        if (tool.getScriptId() == null) {
            throw new IllegalArgumentException("脚本工具必须关联脚本");
        }

        // TODO: 根据工具的inputSchema验证输入参数
        // 目前简单检查输入不为空
        if (input == null) {
            throw new IllegalArgumentException("输入参数不能为空");
        }
    }

    /**
     * 执行脚本
     * 
     * @param script 脚本定义
     * @param input  输入参数
     * @return 执行结果
     * @throws Exception 执行异常
     */
    private Object executeScript(Script script, Object input) throws Exception {
        String inputJson = objectMapper.writeValueAsString(input);

        // 优先使用预编译字节码
        if (script.getCompiledContent() != null && script.getCompiledContent().length > 0) {
            return executeCompiledScript(script, inputJson);
        }

        // 否则实时编译执行
        return compileAndExecuteScript(script, inputJson);
    }

    /**
     * 执行预编译脚本
     */
    private Object executeCompiledScript(Script script, String inputJson) {
        // TODO: 实现从字节码加载类并执行
        // 暂未实现自定义类加载器
        throw new BusinessException("执行预编译脚本尚未实现，请使用实时编译");
    }

    /**
     * 实时编译并执行脚本
     */
    private Object compileAndExecuteScript(Script script, String inputJson) throws Exception {
        // 创建临时目录和源文件
        String className = "ScriptImpl_" + script.getId();
        String scriptCode = generateScriptCode(className, script.getContent());

        Path tempDir = Files.createTempDirectory(Path.of(TEMP_DIR), "script_");
        Path sourceFile = tempDir.resolve(className + ".java");
        Files.writeString(sourceFile, scriptCode, StandardCharsets.UTF_8);

        // 编译源文件
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        if (compiler == null) {
            throw new BusinessException("未找到Java编译器，请确保使用JDK而不是JRE");
        }

        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
        try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) {
            Iterable<? extends JavaFileObject> compilationUnits = fileManager
                    .getJavaFileObjectsFromFiles(Arrays.asList(sourceFile.toFile()));

            StringWriter output = new StringWriter();
            boolean success = compiler.getTask(output, fileManager, diagnostics, null, null, compilationUnits)
                    .call();

            if (!success) {
                StringBuilder sb = new StringBuilder("脚本编译失败:\n");
                for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                    sb.append(diagnostic.toString()).append("\n");
                }
                throw new BusinessException(sb.toString());
            }

            // 加载并执行编译后的类
            try (URLClassLoader classLoader = new URLClassLoader(new URL[] { tempDir.toUri().toURL() })) {
                Class<?> clazz = classLoader.loadClass(className);
                Object instance = clazz.getDeclaredConstructor().newInstance();

                // 执行脚本的execute方法
                String resultJson = (String) clazz.getMethod("execute", String.class).invoke(instance, inputJson);

                // 将JSON结果转换为对象
                if (resultJson != null && !resultJson.isEmpty()) {
                    return objectMapper.readValue(resultJson, Object.class);
                } else {
                    return new HashMap<>();
                }
            }
        } finally {
            // 清理临时文件
            try {
                Files.deleteIfExists(sourceFile);
                Files.deleteIfExists(tempDir);
            } catch (Exception e) {
                logger.warn("清理临时文件失败: " + e.getMessage());
            }
        }
    }

    /**
     * 生成脚本代码
     */
    private String generateScriptCode(String className, String content) {
        StringBuilder sb = new StringBuilder();

        // 添加必要的导入
        sb.append("import com.fasterxml.jackson.databind.ObjectMapper;\n");
        sb.append("import com.fasterxml.jackson.databind.JsonNode;\n");
        sb.append("import java.util.*;\n\n");

        // 创建类定义
        sb.append("public class ").append(className).append(" {\n\n");

        // 添加execute方法
        sb.append("    public String execute(String inputParams) throws Exception {\n");
        sb.append("        ObjectMapper objectMapper = new ObjectMapper();\n");
        sb.append("        JsonNode input = objectMapper.readTree(inputParams);\n\n");

        // 插入用户脚本内容
        sb.append(content);

        // 关闭方法和类定义
        sb.append("\n    }\n");
        sb.append("}\n");

        return sb.toString();
    }
}